| ../. | ||||||||||||||||||||||||
| SEAC10 | ||||||||||||||||||||||||
| MTCT10 - TEDA11 | ||||||||||||||||||||||||
| JAVP31 | ||||||||||||||||||||||||
| HCIK10 - LING11 | ||||||||||||||||||||||||
| FULO01 | ||||||||||||||||||||||||
| FOTO10 | ||||||||||||||||||||||||
| CCP411 - CCP421 | ||||||||||||||||||||||||
Praktisch en vernieuwend met nieuwe media omgaan Verslag zn Demo
Online messaging using KISS and apacheinleidingEen elektronisch communicatiesysteem behelst, door de band genomen, 3 dingen
Goed beschouwd is er dus eigenlijk enkel een manier van authenticatie nodig om een messaging systeem op poten te zetten. Een manier om verzender en ontvanger van elkaar te identificeren, eventueel gekoppeld aan het tijdelijke of voor langere duur opslaan van data (het bericht) We gaan een communicatiesysteem te creeren dat ten alle tijden bereikbaar is, door firewalls heen en in nog onbekende netwerktopologien het gegarandeerd zal doen. De enige manier (i am aware of) om dit in deze wwweb-enabled tijden te doen is door alle communicatie over http heen te layeren. request based webverkeer is de allomtegenwoordige netwerklink die bedrijven huizen en organisaties met elkaar linkt, corporate firewalls en proxies blokeren wel een hoop sites, maar als het goed is zet je een altijd-overal-online messenger niet op zo'n server neer. voordelen bij keuze http(s) als transportmiddelauthentication en dus een manier om gebruikers van elkaar te scheiden is inbegrepen in het protocol bij gebruik van ssl (https) wordt alle informatie encrypted en beveiligd voor man in the middle attacks nadelen bij keuze http(s) als transportmiddelhttp is een request based protocol waardoor enkel met een 'polling' model gewerkt kan worden om server en/of status berichten aan de client door te geven http is een protocol met redelijk veel overhead, zeker met korte berichten is het niet abnormaal als het gemiddelde paketje meer headers dan payload bevat. aan de slag,....vanwege de uitermate geschiktheid als prototyping language kiezen we perl als development taal voor standaard messaging doeleinden hebben we een paar dingen nodig
als spool systeem hadden we kunnen opteren voor een SQL database backend maar de principes van KISS respecterend kiezen we voor het filesystem als data-storage / dbase oplossing. filesystem layout
online messaging, breakdownhet 'revolutionaire' (once upon a time) van icq en aol instant messenger was dat je de online status van je buddies kon zien. Softwarematig is dit eigenlijk niet zo'n byzondere feature; vanaf dat een client vraagt naar de status van anderen is zijn status gelijk geweten door de server. Dit gaat dus vanzelf 'goed'. het enige wat de server moet doen is vertellen wanneer hij zn contacts voor het laatst heeft gezien.... execution flowstandaard programma executie schema loopt als volgt
Om duidelijkheid in het programma te creeren bouw ik een prototype; hoewel een dergerlijke tussenstap tijdrovend kn zijn helpt het om je oplossing te toetsen aan de praktijk. Omdat ik voor prototyping perl gebruik kruipt er ook niet al teveel tijd in een dergelijke quick hack op te zetten bovenstaand command execution schema omgezet in regels code, filelocking wordt eventjes voor de eenvoudigheid weggelaten evenals Tainted data checks en andere, dit telt slechts als voorbeeld
01 #!/usr/bin/perl
02 # rapid prototype for online messenger
03 # (c) 2004 GPL Matthijs P Dalhuijsen
04
05 use CGI qw/:standard/;
06 print header;
07 my $root = "/var/www/thijs/tmp/oma";
08 my $timeout = 60*6;
09 local $\=br;
10
11 # welke (authenticated) user ben ik?
12 defined $ENV{REMOTE_USER} || exit;
13
14 # zijn er wijzigingen in mn data uit te voeren
15 if (param('sendmsg')) {
16 if (-d "$root/".param('sendmsg')."/$ENV{REMOTE_USER}"){
17 print "NYI";
18 } else {
19 print p, "user doesnt like you";
20 }
21 }
22 # zet mijn lastseen time to huidige tijd
23 open(SEEN,">$root/$ENV{REMOTE_USER}/.seen") || die("$!");
24 print SEEN time;
25 close(SEEN);
26 # zijn er ongelezen berichten
27 foreach (<$root/$ENV{REMOTE_USER}/*/*>){
28 open MSG, $_;
29 print $_;
30 print <MSG>;
31 close MSG;
32 unlink $_
33 }
34 # toon huidige status
35 open(CLIST,"$root/$ENV{REMOTE_USER}/.alist") || die("$!");
36 foreach(<CLIST>){
37 /^\s*(\#|$)/ && next;
38 chomp;
39 open(SEEN,"$root/$_/.seen");
40 if ((time - (<SEEN>))<$timeout) {
41 print "$_ is online";
42 } else {
43 print "$_ is offline";
44 }
45 }
Testomgeving OMAMet dit scriptje is de voornaamste functie van een instant messenger al geimplementeerd; de status van de contactpersonen wordt geregistreerd en weergegeven. Instant is ie dus al, nou nog messaging, ... hoewel dat je natuurlijk de telefoon erbij zou kunnen pakken. hier
kan je 'm testen. (username test pass test) interfaceeen programma wordt tegenwoordig pas gesmaakt als het voorzien is van een mooie gui als we javascript toevoegen letten we er op dat voor scriptloze browsers een alternatief voorzien wordt. elke kritieke functie (status, lezen, versturen) van de messenger moet in _elke_ browser draaien; maw. geen frames, geen plaatjes, geen javascript Vormgeving
implementatieomdat we willen dat elk hierboven geschetst onderdeel van de messenger onafhankelijk acties kan versturen en ontvangen maken we een frameset aan waarin de onderdelen zullen leven 01 <html> 02 <head> 03 <title>messenger frameset</title> 04 </head> 05 <frameset rows="*,20" border=0 framespacing=0 framepadding=0 frameborder=0> 06 <frame src="clist.pl" name=clist noresize> 07 <frameset cols="*,30" border=0 framespacing=0 framepadding=0 frameborder=0> 08 <frame src="options.shtml" name=options noresize> 09 <frame src="status.pl" name=status> 10 </frameset> 11 </frameset> 12 <noframes> 13 <!--#Include virtual="noframes.pl" --> 14 </noframes> 15 </html> objectstructuureen objectgeorienteerde manier van werken is eigenlijk altijd een goed idee in eerste instantie bouw ik de scripts, daarna de module
stap 1, een lege modulehoewel dat onze module in eerste instantie geen enkele functionaliteit zal bevatten moet hij wel even aangemaakt wordenMessenger.pm
01 package Messenger;
02 use strict;
03 sub new { # CONSCRUCTOR
04 my $proto = shift;
05 $proto = ref $proto || $proto;
06 my $self = {};
07 bless ($self,$proto);
08 return $self;
09 }
10 1
stap 2, clist.plvervolgens maken we clist.pl aan, de 2 voornaamste functies van dit scriptje zijn:
de programmalogica en communicatie die het scriptje met de module zal uitvoeren bij zijn eerste taak zal ongeveer zo gaan: foreach my $user (@clist) {
print getstatus($user);
}
laten we deze eerste functie in script en module plaatsen
01 #!/usr/bin/perl
02 print "Content-Type: text/html\n\n";
03 use Messenger;
04 my $msgr = Messenger->new();
05 foreach ($msgr->clist()){
06 printf "%s is %s<br>\n",
07 $_,
08 $msgr->status($_) ? "online" : "offline";
09 }
en in Messenger.pm komen er twee lege subjes bij:
10 sub clist {
11 my $self = shift;
12 return "jan","klaas","piet","hein";
13 }
14 sub status {
15 my $self = shift;
16 return 1;
17 }
18 1
options.shtml kan in eerste instantie leegelaten worden, later komen hier de contactlist functies en personal details onder
01 <html> 02 <head> 03 <title>options</title> 04 </head> 05 <body> 06 </body> 07 </html> noframes.plnoframes.pl is perfect om als eerste volledig uit te bouwen, in deze pagina moet alle functionaliteit zitten van de messenger en kan door text only browsers ed gebruikt worden Het executieschema is hetzelfde als bij ons eerste prototype, maar ditmaal maken we gebruik van objecten 01 use CGI qw/:standard/; 02 use Messenger; 03 my $msgr = Messenger->new(); 04 # welke user ben ik? 05 unless (defined $msgr->{user}) { 06 print "nomsgr"; 07 exit; 08 } 09 # setseen 10 $msgr->setseen(int time); 11 if (param('sendmsg')){ 12 if ($msgr->sendmessage(param('to'),param('message'))){ 13 print "messgae sent ok"; 14 } else { 15 print "some error occurred $!"; 16 } 17 } 18 19 local $\=br; 20 map { print $msgr->status($_) ? "$_ online" : "$_ offline" } $msgr->clist; De meeste functionaliteit zit wel in noframes.pl dus kan dit voorlopig als testinterface dienen en kan Messenger.pm uitgebreid worden met enkele ontbrekende functies. Nadat de laatste stubjes overgezet zijn is de API waarschijnlijk volledig;
01 package Messenger;
02 use strict;
03 sub new { # CONSCRUCTOR
04 my $proto = shift;
05 $proto = ref $proto || $proto;
06 my $self = {};
07 bless ($self,$proto);
08 return $self;
09 }
10 sub clist {
11 my $self = shift;
12 return "jan","klaas","piet","hein";
13 }
14 sub status {
15 my $self = shift;
16 return 1;
17 }
18 sub getseen {
19 my $self = shift;
20 return int time;
21 }
22 sub setseen {
23 my $self = shift;
24 return 1;
25 }
26 sub sendmessage {
27 my ($self, $to, $message) = @_;
28 return 0;
29 }
30 sub readmessage {
31 my $self = shift;
32 my $from = shift;
33 return "leeg bericht";
34 }
35 1
en kunnen de stub-routines vervangen worden door sub-routines.
dit is eigenlijk een kwestie van de acties in het prototype scriptje om te zetten naar de net aangemaakte stub module 01 package Messenger; 02 use strict;in de constructor komen wat settings hardcoded te staan; deze kunnen natuurlijk altijd overschreven worden: het blijft perl
03 sub new { # CONSTRUCTOR
04 my $proto = shift;
05 $proto = ref $proto || $proto;
06 my $self = {};
07 bless ($self,$proto);
08 $self->{timeout} = 60*6;
09 $self->{root} = $ENV{HOME} . "/tmp/oma";
10 $self->{user} = $ENV{REMOTE_USER};
11 $self->{home} = $self->{root} . "/" . $self->{user};
12 return $self;
13 }
clist opent eerst de gebruikers contactlist en haalt dan op lijn 17 de newline achter elke naam weg. Hier kan ook een cache geimplementeerd worden zodat niet elke actie die de contactlist gebruikt steeds het filesystem aanspreekt
14 sub clist {
15 my $self = shift;
16 open(CLIST,$self->{home}."/.alist") || return 0;
17 map { chomp; +("$_") } (<CLIST>);
18 }
dan de functies om de 'lastseen' tijd te updaten en te verkrijgen, de sub status kijkt of de gevraagde gebruiker minder dan {timeout} tijd geleden op de server gezien is
19 sub status {
20 my ($self,$req) = @_;
21 return ( int(time) - $self->getseen($req)) < $self->{timeout};
22 }
23 sub getseen {
24 my ($self,$req) = @_;
25 open(SEEN,$self->{root}.'/'.quotemeta($req).'/.seen') || return 0;
26 $req=<SEEN>;chomp;return int $req;
27 }
28 sub setseen {
29 my $self = shift;
30 open(SEEN,">".$self->{home}.'/.seen') || return 0;
31 print SEEN int time;
32 close(SEEN);
33 }
en dan de 2 functies om berichten te lezen en te versturen, er wordt geen history bijgehouden dus nadat het bericht gelezen is mag het verwijderd worden
34 sub sendmessage {
35 my ($self, $to, $message) = @_;
36 my $msgdir = $self->{root}.'/'.quotemeta($to).'/'.quotemeta($self->{user});
37 if ( -d $msgdir ) {
38 open(MSG,">>".$msgdir.'/'.int(time)) || return 0;
39 print MSG $message;
40 close MSG;
41 return 1;
42 } else {
43 return 0;
44 }
45 }
46 sub readmessage {
47 my $self = shift;
48 my $from = shift;
49 my $msgloc = $self->{root}.'/'.quotemeta($self->{user}).'/'.quotemeta($from).'/msg';
50 if ( -f $msgloc ) {
51 open(MSG,$msgloc);
52 my @tmpo = (<MSG>);
53 close MSG;
54 unlink $msgloc;
55 return @tmpo;
56 } else {
57 return 0;
58 }
59 }
60 1
referenties: perldoc cpan | ||||||||||||||||||||||||
| ANIM31 | ||||||||||||||||||||||||